/**
 * Created by arvin on 2017/3/31 0031.
 */
(function ($) {
    'use strict';

    // TOOLS DEFINITION
    // ======================

    var cachedWidth = null;

    // it only does '%s', and return '' when arguments are undefined
    var sprintf = function (str) {
        var args = arguments,
            flag = true,
            i = 1;

        str = str.replace(/%s/g, function () {
            var arg = args[i++];

            if (typeof arg === 'undefined') {
                flag = false;
                return '';
            }
            return arg;
        });
        return flag ? str : '';
    };
    var compareList = function(a,b){
        var str1= (a||[]).jion(''),
            str2= (b||[]).jion('');
        return str1==str2;
    };
    var bindEvent = function(obj,events){
        var _events = keys(events);
        $(_events).each(function(i,eve){
            var trigger = eve.split(' ')[0],
            _target = eve.split(' ').slice(1).join(' ');
            $(obj).find(_target).off(trigger).on(trigger,events[eve]);

        })
    };
    var _keys = function() {
        var hasOwnProperty = Object.prototype.hasOwnProperty,
            hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
            dontEnums = [
                'toString',
                'toLocaleString',
                'valueOf',
                'hasOwnProperty',
                'isPrototypeOf',
                'propertyIsEnumerable',
                'constructor'
            ],
            dontEnumsLength = dontEnums.length;

        return function(obj) {
            if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
                throw new TypeError('Object.keys called on non-object');
            }

            var result = [], prop, i;

            for (prop in obj) {
                if (hasOwnProperty.call(obj, prop)) {
                    result.push(prop);
                }
            }

            if (hasDontEnumBug) {
                for (i = 0; i < dontEnumsLength; i++) {
                    if (hasOwnProperty.call(obj, dontEnums[i])) {
                        result.push(dontEnums[i]);
                    }
                }
            }
            return result;
        };
    };
    var keys =function(obj){
        if(_ instanceof Function){
            return _.keys(obj)
        }else if(Object.keys){
            return Object.keys(obj);
        }else{
             return _keys(obj);
        }
    };
    Array.prototype.insert=function(i,record){
        var a = this.slice(0,i),b = this.slice(i),
        list = record instanceof Array ? record:[record];
        return  a.concat(list).concat(b);
    };
    // TreeGrid CLASS DEFINITION
    // ======================

    var TreeGrid = function (el, options) {
        this.options = options;
        this.$el = $(el);
        this.init();
    };

    TreeGrid.DEFAULTS = {
        /** defaluts options**/
        classes:'tree-grid-table table table-striped table-hover',
        fixedheader:true,
        fixedcolumns:true,
        expandall:false,
        column:[],
        data:[],
        /** defaluts options**/
        formatLoadingMessage:function(){
            return 'Loading, please wait...';
        },
        formatnotData:function(){
            return 'no Data';
        },
        rootpath:'tree',
        /** defaluts fun**/

        onAll:function(){
            return false;
        },
        onExpand:function(node,tree,expandall){
            if(this.isBeaf(node)||node.nodeData.status=='loading'){
                return ;
            }
            if(this.checkNoLoaded(node)){
                 tree.trigger('dataRefresh',{type:'loading',node:node},tree);

                tree.loadNode(node,tree);
                return;
            }
            if(expandall){
                $(node.child).each(function(i,child){
                    tree.trigger('expand',child,tree,expandall);
                })

            }
            tree.trigger('dataRefresh',{type:'expand',node:node},tree);

        },
        onCollapse:function(node,tree){
            if(this.isBeaf(node)){
                return ;
            }

            tree.trigger('dataRefresh',
                {type:'collapse',node:node},tree);
        },
        removeNode:function(node,tree){

            tree.trigger('dataRefresh',
                {type:'remove',node:node},tree);
        },
        isBeaf:function(node){
            return node.nodeData.isbeaf
        },
        checkNoLoaded:function(node){
            return node.child.length==0
        },
        getAllChildNode:function(node,tree){

        },
        getChildNode:function(node,tree){
            return node['child'];
        },
        getNodeData:function(node,tree){
           return node['nodeData'];
       },
        showTreeRoot:function(){
            return this.root;
        },
        onDataRefresh:function(event,tree){
             tree.changeDataFormTree(event,tree);
        },
        onRefreshView:function(event,tree){
            var index = event.index,
                list = event.list,
                type = event.type;
            if(tree.viewData.length==0){
                return;
            }
            if(type=='expand'||type=='collapse'||type=='loading'){
                tree.refreshRowStatus(index,list,tree);
            }



        },
        onTreeIconClick:function(event,tree){
             if(event.isbeaf){
                return;
            }
            var path = event.row.attr('data-treeid').split('_');
            var node = tree.getNodeByPath(path,null,tree);
            if(event.status=='open'){
               tree.trigger('collapse',node,tree);
            }else if(event.status=='close'){
                tree.trigger('expand',node,tree);
            }


        }
    };
    TreeGrid.COLUMN_DEFAULTS = {


    };
    TreeGrid.EVENTS = {
        'all.bs.tree': 'onAll',
        'expand.bs.tree':'onExpand',
        'collapse.bs.tree':'onCollapse',
        'dataRefresh.bs.tree':'onDataRefresh',
        'refreshView.bs.tree':'onRefreshView',
        'treeIconClick.bs.tree':'onTreeIconClick',


    };

    TreeGrid.prototype.init = function () {
        this.data = [];
        this.root ={
            nodeData:{
                floor:-1,
                path:[this.options.rootpath]
            },
            child:[]
        };
        this.viewData=[];

        this.initContainer();
        this.initTable();
        this.initData();
        this.initServer();
        this.initBody();
        this.initHeader();
        this.initFixedColumns();
        this.initSrcollBar();


    };
    TreeGrid.prototype.initTable = function (){
        //
        //

    };
    TreeGrid.prototype.initHeader = function (){
        if(!this.options.fixedheader){
            return ;
        }


        var $head = this.$head.clone(true);
        this.$treeHeader.find('table').html($head);

    };
    TreeGrid.prototype.initFixedColumns = function (){
        var tree = this;
        if(!this.options.fixedcolumns){
            return ;
        }
        var $table = this.$el.clone(true);
        $table.attr('id','_'+this.$el.attr('id'));
        this.$treeFixedColumns.html('').append($table);

        $("tbody tr").hover(
            function () {
                var index =$(this).index();
                tree.$body.find('tr').eq(index).addClass("hover");
                tree.$treeFixedColumns.find('tbody tr').eq(index).addClass("hover");

            },
            function () {
                var index =$(this).index();
                tree.$body.find('tr').eq(index).removeClass("hover");
                tree.$treeFixedColumns.find('tbody tr').eq(index).removeClass("hover");
            }
        );




    };
    TreeGrid.prototype.initSrcollBar = function (){
        //
        //

    };
    TreeGrid.prototype.changeDataFormTree = function (event,tree){
            var nodes = event.node instanceof Array ? event.node:[event.node];
            $(nodes).each(function(i,node){
                tree.RefreshData(node,event.type);
            });

    };
    TreeGrid.prototype.RefreshData = function(node,type){
        var index = this.getIndexByNode(node),
        list= [];
        this.getDataFormNode(list,node,this,type=='expand');
        if(type=='add'){
            if(index==-1){
                this.data=list;
            }else{
                this.data = this.data.insert(index,list);
            }
        }else if(type=='update'){

        }else if(type=='loading'){
            list[0].status='loading';
        }else if(type=='collapse'){
           $(list).each(function(i,row){
                 row.status = row.status=='loading'?'loading': 'close';
                 row.hide=true;
           });
           list[0].hide=false;

        }else if(type=='expand'){

            $(list).each(function(i,row){

                if(row.floor -1 == node.nodeData.floor){
                    row.hide= false;
                }

            });
            list[0].status='open';

        }else if(type=='remove'){

        }

        this.trigger('refreshView',{index:index,list:list,type:type},this);

    };
    TreeGrid.prototype.getDataFormNode = function(list,node,tree){
        if(node.nodeData.floor!=-1){//
             list.push(node.nodeData);
        }
        if(node.child.length==0){
            return;
        }
        $(node.child).each(function(i,child){
            tree.getDataFormNode(list,child,tree);

        });

    };
    TreeGrid.prototype.getIndexByNode = function(node){
        var datas= this.data,dataId=node.nodeData.path.join('-'),index=0;
        if(node.nodeData.floor==-1){
            return -1;
        }
        $(datas).each(function(i,data){
            if(data.path.join('-')==dataId){
                index = i;
                return false;
            }

        });
        return index;

    };
    TreeGrid.prototype.initData = function (){
        if(!this.options.data.length){
            return;
        }
        this.addData2Node(this.root.nodeData,this.options.data,this);
        this.trigger('dataRefresh',
            {type:'add',node:[this.root]},this);

    };
    TreeGrid.prototype.addData2Node =function(nodeData,records,tree){
        var parentNode = tree.getNodeFormParent(nodeData),
            rootNode =  parentNode;

          $.each(records,function(i,record){
            var row = {
                nodeData:{
                    isbeaf:record.isbeaf,
                    floor:record.floor,
                    status:'close',
                    hide:false,
                    data:record,
                    path:[],
                },
                child:[]
            },
             oldindex= 0,
             oldfloor = parentNode.nodeData.floor+1;//默认新层级 比父层级多一个

            if(oldfloor==record.floor){
                parentNode = parentNode;
            }else if(oldfloor>record.floor){// 回溯到
                parentNode = tree.getParentNode(oldfloor-record.floor,parentNode,rootNode,tree);

            } else if(oldfloor<record.floor){
                 parentNode = parentNode.child.slice(-1)[0];
              }
              oldindex = parentNode.child.length;
              row.nodeData.path = parentNode.nodeData.path.concat([oldindex]);
              parentNode.nodeData.status='open';
              parentNode.child.push(row);

          });

    };
    TreeGrid.prototype.initBody = function (){
        var that=this,
            columns = this.options.column,
            datas = this.data;
        this.$body = this.$el.find('>tbody');
        this.$head = this.$el.find('>thead');
        if (!this.$body.length) {
            this.$body = $('<tbody></tbody>').appendTo(this.$el);
        }
        if (!this.$head.length) {
            this.$head = $('<thead></thead>').appendTo(this.$el);
        }

        //create header
        this.$head.append(this.formatHeader(columns));

        //create body
        $(datas).each(function(i,data){
            that.$body.append(that.formatRow(data,columns));
        });
        this.viewData  = this.data;

    };
    TreeGrid.prototype.formatRow = function(row,columns){
        var $tr=$('<tr></tr>'),tree=this;
        $tr.attr('data-floor',row.floor);
        $tr.attr('data-status',row.status);
        $tr.attr('data-isbeaf',row.data.isbeaf);
        $tr.attr('data-treeid',row.path.join('_'));
        $tr.attr('data-oid',row.data.oid);
        $tr.attr('data-hide',row.hide);
        $(columns).each(function(i,column){
            var $td=$('<td></td>');
            if(column.type=='checkbox'){
                $td.append('<input name="treeSelectItem" type="checkbox" />');
                $td.find('[ name="treeSelectItem"]')
                    .prop('checked',row.checked)
                    .prop('disabled',row.disabled).off('click').on('click',function(){
                    if(this.disabled){
                        retrun;
                    }
                      row.checked = this.checked;

                })
            }else{
                if(column.formater instanceof Function){
                    $td.html(column.formater(
                        row.data[column.fieldIndex],row,column
                    ));

                }else{
                    $td.html(row.data[column.fieldIndex]);

                }

                if(column.tdevents){
                    bindEvent($td,column.tdevents);
                }
            }
            $td.addClass(column.tdcss);
            $td.attr('data-fixedcell',column.fixedCell);
            $td.width(column.width);
            $tr.append($td);
        });

        $tr.find(this.options.treeIcon).off('click').on('click',function(){
            tree.trigger('treeIconClick',{row:$tr,status:row.status,isbeaf:row.data.isbeaf},tree);
        });
        return $tr;
    };

    TreeGrid.prototype.refreshRowStatus = function(index,list,tree){
        var $tr=tree.$body.find('tr').eq(index);
        $(list).each(function(i,row){
            $tr.attr('data-hide',row.hide);
            $tr.attr('data-status',row.status);

            $tr.find('[ name="treeSelectItem"]')
                .prop('checked',row.checked)
                .prop('disabled',row.disabled);
            $tr=$tr.next();
        });
        tree.initFixedColumns();

    };
    TreeGrid.prototype.refreshRowData = function(index,list,tree){
        var $tr=tree.$body.find('tr').eq(index);
        $(list).each(function(i,row){
            $tr.attr('data-hide',row.hide);
            $tr.attr('data-status',row.status);
            $tr=$tr.next();
        });
    }
    TreeGrid.prototype.formatHeader = function(columns){
        var $tr=$('<tr></tr>'),tree=this;
        $(columns).each(function(i,column){
            var $th=$('<th></th>');
            if(column.type=='checkbox'){
                $th.append('<input name="treeSelectAll" type="checkbox" />');
                $th.find('[name="treeSelectAll"]').off('click').on('click',function(){
                    if(this.disabled){
                     retrun;
                    }
                     var checked = $(this).prop('checked');
                    $('[name="treeSelectAll"]').prop('checked',checked);
                     tree.checkedAll(checked);
                })
            }else{
                $th.html(column.title);
                $th.attr('data-fieldindex',column.fieldIndex);

                if(column.thevents){
                    bindEvent($th,column.thevents);
                }
            }
            $th.addClass(column.thcss);
            $th.width(column.width);
            $th.attr('data-fixedcell',column.fixedCell);
           $tr.append($th);
        });
        return $tr;
    };
    TreeGrid.prototype.initServer = function (){

    };
    TreeGrid.prototype.initContainer = function () {
        this.$container = $([
            '<div class="tree-grid">',
                '<div class="tree-grid-toolbar"></div>',
                '<div class="tree-grid-container">',
                    '<div class="tree-grid-header none"><table></table></div>',
                    '<div class="tree-grid-fixed none"><table></table></div>',
                    '<div class="tree-grid-body">',
                       '<div class="tree-grid-loading none">',
                        this.options.formatLoadingMessage(),
                        '</div>',
                    '</div>',
            '</div>'
        ].join(''));
        this.$container.insertAfter(this.$el);
        this.$treeContainer = this.$container.find('.tree-grid-container');
        this.$treeToolbar = this.$container.find('.tree-grid-toolbar');
        this.$treeHeader = this.$container.find('.tree-grid-header');
        this.$treeBody = this.$container.find('.tree-grid-body');
        this.$treeLoading = this.$container.find('.tree-grid-loading');
        this.$treeFixedColumns = this.$container.find('.tree-grid-fixed');
        this.$treeBody.append(this.$el);
        this.$el.addClass(this.options.classes);
        if(this.options.fixedheader){
            this.$treeHeader.removeClass('none');
            this.$treeHeader.find('table').addClass(this.$el[0].className);
        }
        if(this.options.fixedcolumns){
            this.$treeFixedColumns.removeClass('none');
            this.$treeFixedColumns.find('table').addClass(this.$el[0].className);
        }
    };


    TreeGrid.prototype.trigger = function (name) {
        var args = Array.prototype.slice.call(arguments, 1);

        name += '.bs.tree';
        this.options[TreeGrid.EVENTS[name]].apply(this.options, args);
        this.$el.trigger($.Event(name), args);

        this.options.onAll(name, args);
        this.$el.trigger($.Event('all.bs.tree'), [name, args]);
    };

    TreeGrid.prototype.getParentNode = function(level,node,rootNode,tree){

        var path = node.nodeData.path.slice(0,-1*level);
        return  tree.getNodeByPath(path,rootNode,tree);
    };
    TreeGrid.prototype.getNodeByPath = function(path,rootNode,tree){
        var node = rootNode||this.root, i= 1,depth=path.length;
        while(i<depth){
            node = node.child[path[i++]];
        }
        return node;

    };
    TreeGrid.prototype.getNodeFormParent = function(nodeData,rootNode){
        var floor=nodeData.floor,depth=floor+ 1,
            node = rootNode||this.root;
        if(floor==-1){
            return node;
        }

        do{
            node = node.child[path[floor-depth]];
            depth--;
        } while(depth!=0);
        return node;

    };
    TreeGrid.prototype.loadNode = function(node,tree){
        console.log(node);
    };
    TreeGrid.prototype.collapseAll = function (){
        var tree = this;
        $(tree.root.child).each(function(i,node){
            tree.trigger('collapse',node,tree);
        })

    };
    TreeGrid.prototype.expandAll = function (){
        var tree = this;
       // this.options.expandAll =true;

        $(tree.root.child).each(function(i,node){
            tree.trigger('expand',node,tree,true);
        })

    };
    TreeGrid.prototype.checkedAll = function (checked){
        $(this.data).each(function(i,row){
            if(!row.disabled){
                row.checked = checked;
            }

        });
        this.refreshRowStatus(0,this.data,this);
    }
    TreeGrid.prototype.getData = function (){
        return this.data;
    };
    TreeGrid.prototype.getAllSelections = function (){
        var list = [];
        $(this.data).each(function(i,row){
            if(row.checked){
                list.push(row);
            }
        })
        return  list;
    };
    TreeGrid.prototype.getSelections = function (){
        var list = [];
        $(this.data).each(function(i,row){
            if(row.checked){
                list.push(row);
            }
        })

        return  list[0]?list[0]:list;
    };
    // TreeGrid PLUGIN DEFINITION
    // =======================

    var allowedMethods = [
        'getOptions',
        'getSelections', 'getAllSelections', 'getData',
        'refresh',
        'destroy',
        'showLoading', 'hideLoading',
        'refreshOptions',
        'refreshColumn',
        'expandAll', 'collapseAll'

    ];

    $.fn.TreeGrid = function (option) {
        var value,
            args = Array.prototype.slice.call(arguments, 1);

        this.each(function () {
            var $this = $(this),
                data = $this.data('treegrid.tree'),
                options = $.extend({}, TreeGrid.DEFAULTS, $this.data(),
                    typeof option === 'object' && option);

            if (typeof option === 'string') {
                if ($.inArray(option, allowedMethods) < 0) {
                    throw new Error("Unknown method: " + option);
                }

                if (!data) {
                    return;
                }

                value = data[option].apply(data, args);

                if (option === 'destroy') {
                    $this.removeData('treegrid.tree');
                }
            }

            if (!data) {
                $this.data('treegrid.tree', (data = new TreeGrid(this, options)));
            }
        });

        return typeof value === 'undefined' ? this : value;
    };

    $.fn.TreeGrid.Constructor = TreeGrid;
    $.fn.TreeGrid.defaults = TreeGrid.DEFAULTS;
    $.fn.TreeGrid.columnDefaults = TreeGrid.COLUMN_DEFAULTS;
    $.fn.TreeGrid.methods = allowedMethods;
    $.fn.TreeGrid.utils = {
        sprintf: sprintf,
        compareList:compareList,
        keys:keys,
        bindEvent:bindEvent

    };

    // TreeGrid INIT
    // =======================

    $(function () {
        $('[data-toggle="tree"]').TreeGrid();
    });
})(jQuery);
